package com.wodan.zhongjinjicang.frame;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Sets;
import com.wodan.zhongjinjicang.common.constants.ClientApiConstants;
import com.wodan.zhongjinjicang.common.constants.CommonConstants;
import com.wodan.zhongjinjicang.common.exception.BusinessException;
import com.wodan.zhongjinjicang.common.redis.JedisClient;
import com.wodan.zhongjinjicang.common.utils.JsonUtils;
import com.wodan.zhongjinjicang.enums.BusinessErrorEnum;
import com.wodan.zhongjinjicang.model.QueryParam;
import com.wodan.zhongjinjicang.model.UserBean;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

/**
 * Json业务处理的公共基类
 * 
 * @ClassName: JsonBusinessMethodServiceTemplate
 * @author Administrator
 * @date 2015-1-16 上午11:07:43
 * @history
 * 
 */
public abstract class JsonBusinessMethodServiceTemplate implements JsonBusinessMethodService {
	private static Logger logger = LoggerFactory.getLogger(JsonBusinessMethodServiceTemplate.class);

	@Autowired
	private JedisClient jedisClient;

	@Value("${REDIS_USER_SESSION_KEY}")
	private String REDIS_USER_SESSION_KEY;
	@Value("${SSO_SESSION_EXPIRE}")
	private Integer SSO_SESSION_EXPIRE;

	private static final Set<Character> HTML_SENSITIVE_CHAR_SET;
	static {
		Set<Character> tempSet = new HashSet<Character>();
		tempSet.add(Character.valueOf('<'));
		tempSet.add(Character.valueOf('>'));

		HTML_SENSITIVE_CHAR_SET = Collections.unmodifiableSet(tempSet);
	}

	private static final Set<String> URL_LEGAL_PREFIX;
	static {
		Set<String> tempSet = Sets.newHashSet();
		tempSet.add("http://");
		tempSet.add("https://");

		URL_LEGAL_PREFIX = Collections.unmodifiableSet(tempSet);
	}

	private static final Set<Character> URL_LEGAL_CHAR_SET;
	static {
		StringBuilder sb = new StringBuilder();
		sb.append("abcdefghijklmnopqrstuvwxyz");
		sb.append("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
		sb.append("0123456789");
		sb.append("-:/%?_-=.&");

		Set<Character> tempSet = Sets.newHashSet();
		for (int i = 0; i < sb.length(); i++) {
			tempSet.add(sb.charAt(i));
		}
		URL_LEGAL_CHAR_SET = Collections.unmodifiableSet(tempSet);
	}

	protected abstract JSONObject doExecute(JSONObject content,String sessionId);

	@Override
	public JSONObject execute(JSONObject busJsonObj) {
		// 更新session生命周期
//		CommonSessionInterface sessionCache = getCommonSessionInterface();
//		sessionCache.expireSession();

		JSONObject content = busJsonObj.getJSONObject(ClientApiConstants.Data);
		String sessionId = busJsonObj.getString(ClientApiConstants.SESSION_ID);

		if (content == null) {
			logger.warn("客户端请求信息缺少data内容.");
			throw new BusinessException(BusinessErrorEnum.ERROR.getCode(),
					BusinessErrorEnum.ERROR.getDesc(), false);
		}

		// 根据sessionId判断是否需要登录
		if (isNeedLogin()) {
			if(!isExistSession(sessionId))
				throw new BusinessException(BusinessErrorEnum.ERROR_USER_NOT_LOGIN.getCode(),
						BusinessErrorEnum.ERROR_USER_NOT_LOGIN.getDesc(), false);
		}
// 		else { // 判断是否需要session信息
//			if (isNeedSession()) {
//				if (!sessionCache.sessionIsInit()) {
//					throw new BusinessException(BusinessErrorEnum.ERROR_SESSION_NOT_EXIST.getCode(),
//							BusinessErrorEnum.ERROR_SESSION_NOT_EXIST.getDesc(), false);
//				}
//			}
//		}

		// 报文中不能携带html敏感字符
//		checkHtmlSensitiveWord(content);
		
		// 进行必填字段校验,如果不符合要求,直接抛出异常
		checkRequiredParams(content);
		
		// 在子类中实现预校验
//		doDerivedClassPublicCheck(clientIp, content);

		return doExecute(content,sessionId);
	}



	/**
	 * 校验必填字段
	 * 
	 * @Description:
	 * @param content
	 */
	private void checkRequiredParams(JSONObject content) {
		String[] requiredParams = getRequiredParams();
		if (ArrayUtils.isEmpty(requiredParams)) {
			return;
		}

		for (String paramName : requiredParams) {
			if (!content.containsKey(paramName)) {
				throw new BusinessException(BusinessErrorEnum.ERROR.getCode(), "客户端请求缺少必填字段, 字段名：" + paramName, false);
			}

			Object object = content.get(paramName);
			if (object == null) {
				throw new BusinessException(BusinessErrorEnum.ERROR.getCode(), "客户端请求缺少必填字段, 字段名：" + paramName, false);
			}

			if (object instanceof JSONArray) {
				JSONArray jsonArray = content.getJSONArray(paramName);
				if (jsonArray.size() == 0) {
					throw new BusinessException(BusinessErrorEnum.ERROR.getCode(), "客户端请求缺少必填字段, 字段名：" + paramName,
							false);
				}
			} else if (object instanceof JSONObject) {
				JSONObject jsonObject = content.getJSONObject(paramName);
				if (jsonObject.isEmpty()) {
					throw new BusinessException(BusinessErrorEnum.ERROR.getCode(), "客户端请求缺少必填字段, 字段名：" + paramName,
							false);
				}
			} else {
				String string = object.toString();
				if (StringUtils.isBlank(string)) {
					throw new BusinessException(BusinessErrorEnum.ERROR.getCode(), "客户端请求缺少必填字段, 字段名：" + paramName,
							false);
				}
			}
		}

	}

	/**
	 * 加入需要校验的必填字段 子类必须实现，如果没有需要校验的必填字段，则返回null
	 * 
	 * @Description:
	 * @return
	 */
	protected abstract String[] getRequiredParams();

	/*
	/**
	 * 需要在子类中进行的校验
	 * @Description:
	 * @param clientIp
	 * @param content
	 *//*
	protected abstract void doDerivedClassPublicCheck(String clientIp, JSONObject content);

	*//**
	 * 进行Url格式校验
	 * 
	 * @Description:
	 * @param content
	 *//*
	protected void checkUrlFieldFormat(JSONObject content) {
		JsonUtils.workAll(null, content, new JsonWorkHandler() {
			@Override
			public void workField(String key, Object value) {
				if (!key.contains("url")) {
					return;
				}

				String valueStr = value.toString();
				// 校验url前缀
				checkUriPrefix(key, valueStr);

				// 校验url内容
				checkUrlContent(key, valueStr);
			}

			*//**
			 * 校验url内容
			 * 
			 * @Description:
			 * @param key
			 * @param valueStr
			 *//*
			private void checkUrlContent(String key, String valueStr) {
				for (Character ch : valueStr.toCharArray()) {
					if (URL_LEGAL_CHAR_SET.contains(ch)) {
						continue;
					}
					throw new BusinessException(BusinessErrorEnum.ERROR.getCode(), "字段" + key
							+ "为url类型，只能包含url合法字符，当前非法字符为:" + ch);
				}
			}

			*//**
			 * 校验url前缀
			 * 
			 * @Description:
			 * @param key
			 * @param valueStr
			 *//*
			private void checkUriPrefix(String key, String valueStr) {
				for (String prefix : URL_LEGAL_PREFIX) {
					if (valueStr.startsWith(prefix)) {
						return;
					}
				}

				throw new BusinessException(BusinessErrorEnum.ERROR.getCode(), "字段" + key
						+ "为url类型，但是没有以http或https开头，当前url为：" + valueStr);
			}
		});
	}

	*//**
	 * 校验html敏感字符
	 * 
	 * @Description:
	 * @param content
	 *//*
	private void checkHtmlSensitiveWord(JSONObject content) {
		String contentString = content.toString();
		for (int i = 0; i < contentString.length(); i++) {
			char ch = contentString.charAt(i);
			if (HTML_SENSITIVE_CHAR_SET.contains(Character.valueOf(ch))) {
				throw new BusinessException(BusinessErrorEnum.ERROR_HTML_SENSITIVE_WORD.getCode(),
						BusinessErrorEnum.ERROR_HTML_SENSITIVE_WORD.getDesc(), false);
			}
		}
	}

	protected abstract JSONObject doExecute(String clientIp, JSONObject content);

	*//**
	 * @Description: 返回业务操作是否依赖session
	 * @return
	 *//*
	protected abstract boolean isNeedSession();

	*//**
	 * @Description: 返回业务操作是否需要用户登录
	 *            客户端上传的content内容
	 * @return
	 */
	protected abstract boolean isNeedLogin();

	/**
	 * 获取通用的session接口
	 * @Description:
	 * @return
	 *//*
	protected abstract CommonSessionInterface getCommonSessionInterface();
	
	*//**
	 * 解析分页参数
	 * 
	 * @Description:
	 * @param content
	 * @return
	 */
	protected QueryParam parseQueryParam(JSONObject content) {
		JSONObject queryParamObject = content.getJSONObject(CommonConstants.QUERY_PARAM);
		if (queryParamObject == null) {
			return new QueryParam();
		}

		return JSONObject.toJavaObject(queryParamObject, QueryParam.class);
	}

	private boolean isExistSession(String sessionId){
		if(null==getUserBySessionId(sessionId)){
			return false;
		}
		return true;
	}

	private UserBean getUserBySessionId(String sessionId) {

		//根据token从redis中查询用户信息
		String json = jedisClient.get(REDIS_USER_SESSION_KEY + ":" + sessionId);
		//判断是否为空
		if (StringUtils.isBlank(json)) {
			return null;
		}
		//更新过期时间
		jedisClient.expire(REDIS_USER_SESSION_KEY + ":" + sessionId, SSO_SESSION_EXPIRE);

		//返回用户信息
		return JsonUtils.jsonToPojo(json, UserBean.class);
	}
	
	
	/*/**
	* @Description: 将分页信息封装至RowBounds
	* @param page 当前页
	* @param rows 每页条数
	* @return
	 *//*
	protected RowBounds pageConver(int page, int rows) {
		if(page < 1 ){
			page = 1 ;
		}
		if( rows < 0 ){
			rows = 10;
		}
		int offset = (page - 1) * rows;
		int limit = rows;
		return new RowBounds(offset, limit);
	}
	

	*//**
	 * 生成分页查询需要的结果
	 * 
	 * @Description:
	 * @param key
	 * @param dataArray
	 * @return
	 *//*
	protected JSONObject createPageQueryResultObject(QueryParam queryParam, String dataKey, Object dataArray) {
		JSONObject resultJson = new JSONObject();

		resultJson.put(CommonConstants.QUERY_PARAM, queryParam);
		resultJson.put(dataKey, dataArray);

		return resultJson;
	}*/
}
